package main

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

func main() {

	var exp string
	//3+2*6-2+3*4-88*77
	for {
		fmt.Println("请输入表达式：")
		_, err := fmt.Scanln(&exp)
		if err != nil {
			fmt.Println("输入有误，")
			continue
		}
		if exp == "exit" {
			break
		}
		res := CalResByExp(exp)
		fmt.Println("结果：", res)
	}
	fmt.Println("结束程序")

}

// CalResByExp
//
//	@Description: 3+2*6-2+3*4-88*77
//	@param exp
//	@return int
func CalResByExp(exp string) int {
	characters, numCount, charCount := parseExp(exp)
	var res int
	num := &NumStack{
		Capacity: numCount,
		TopIndex: -1,
		Elements: make([]int, numCount),
	}
	char := &CharStack{
		Capacity: charCount,
		TopIndex: -1,
		Elements: make([]string, charCount),
	}

	for _, v := range characters {
		if !IsNumber(v) {
			// 运算符,如果栈为空，直接入栈
			if char.IsEmpty() {
				char.Push(v)
			} else {
				// 栈不为空，比较优先级
				topChar := char.Pop()
				topPriority := GetCharPriority(topChar) //栈顶符号的优先级
				curPriority := GetCharPriority(v)       //当前符号的优先级
				if curPriority > topPriority {          //当前优先级更高，则将两个符号入栈
					char.Push(topChar)
					char.Push(v)
				} else {
					// 否则，则取出两个数字，用栈顶符号进行计算，再将计算结果放入数字栈顶
					n1 := num.Pop()
					n2 := num.Pop()
					tempRes := calculate(n2, n1, topChar)
					num.Push(tempRes)
					// 当前符号入栈
					char.Push(v)
				}
			}
		} else {
			// 数字,直接入栈
			n, _ := strconv.Atoi(v)
			num.Push(n)
		}
	}

	// 循环结束后，栈中剩余的符号，依次计算
	for !char.IsEmpty() {
		pop := char.Pop()            //获取栈顶符号
		n1 := num.Pop()              //栈顶数字
		n2 := num.Pop()              //栈顶数字
		res = calculate(n2, n1, pop) //计算
		// 计算结果入栈
		num.Push(res)
	}
	return res
}

type NumStack struct {
	Capacity int // 最大容量
	TopIndex int // 栈顶的index
	Elements []int
}

type CharStack struct {
	Capacity int // 最大容量
	TopIndex int // 栈顶的index
	Elements []string
}

func (s *NumStack) Push(e int) {
	if s.TopIndex == s.Capacity-1 {
		panic(errors.New("数字-栈满"))
	}
	s.TopIndex++
	s.Elements[s.TopIndex] = e

}

func (s *NumStack) Pop() int {
	if s.TopIndex == -1 {
		panic(errors.New("数字-栈空"))
	}
	e := s.Elements[s.TopIndex]
	s.Elements[s.TopIndex] = 0
	s.TopIndex--
	return e
}

func (s *NumStack) IsEmpty() bool {
	return s.TopIndex == -1
}

func (c *CharStack) Push(e string) {
	if c.TopIndex == c.Capacity-1 {
		panic(errors.New("符号-栈满"))
	}
	c.TopIndex++
	c.Elements[c.TopIndex] = e

}
func (c *CharStack) Pop() string {
	if c.TopIndex == -1 {
		panic(errors.New("符号-栈空"))
	}
	e := c.Elements[c.TopIndex]
	c.Elements[c.TopIndex] = ""
	c.TopIndex--
	return e
}
func (c *CharStack) IsEmpty() bool {
	return c.TopIndex == -1
}

func GetCharPriority(c string) int {
	switch c {
	case "+":
		return 1
	case "-":
		return 1
	case "*":
		return 2
	case "/":
		return 2
	default:
		return 0
	}
}
func calculate(n1, n2 int, c string) int {
	switch c {
	case "+":
		return n1 + n2
	case "-":
		return n1 - n2
	case "*":
		return n1 * n2
	case "/":
		return n1 / n2
	default:
		return 0
	}
}

func IsNumber(c string) bool {
	if c == "+" || c == "-" || c == "*" || c == "/" {
		return false
	}
	return true
}

// parseExpression
//
//	@Description: 解析3+2*6-2+3*4-88*77
//	@param expression
//	@return []string
func parseExpression(expression string) []string {
	var chars []string
	var currentNumber strings.Builder

	for _, char := range expression {
		if unicode.IsDigit(char) {
			currentNumber.WriteRune(char)
		} else {
			if currentNumber.Len() > 0 {
				chars = append(chars, currentNumber.String())
				currentNumber.Reset()
			}
			chars = append(chars, string(char))
		}
	}

	// 如果最后一个字符是数字，需要将其添加到 chars 中
	if currentNumber.Len() > 0 {
		chars = append(chars, currentNumber.String())
	}

	return chars
}

// parseExpression
//
//	@Description: 解析3+2*6-2+3*4-88*77
//	@param expression
//	@return []string
func parseExp(expression string) ([]string, int, int) {
	var slice []string = make([]string, 0)
	numCount := 0
	charCount := 0
	sliceList := strings.Split(expression, "")
	var temp = ""
	for _, str := range sliceList {
		if !IsNumber(str) {
			if temp != "" {
				charCount++
				slice = append(slice, temp)
				temp = ""
			}
			temp = str
			numCount++
			slice = append(slice, temp)
			temp = ""
		} else {
			temp += str
		}
	}
	if temp != "" {
		slice = append(slice, temp)
		numCount++
	}

	_, f := strconv.Atoi(slice[0])
	_, l := strconv.Atoi(slice[len(slice)-1])
	if f != nil || l != nil {
		panic("首尾必须为数字")
	}
	return slice, numCount, charCount
}
